package emuLoader.gui.manager;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Path;
import java.util.ResourceBundle;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.stage.DirectoryChooser;
import nayasis.common.device.input.GamePadEvent;
import nayasis.common.device.input.GamePadEventHandler;
import nayasis.common.device.input.GamePadEventManager;
import nayasis.common.log.NLogger;
import nayasis.common.model.NData;
import nayasis.common.model.NMultiData;
import nayasis.common.ui.javaFx.controller.NfxCombo;
import nayasis.common.ui.javaFx.controller.NfxTable;
import nayasis.common.ui.javaFx.dialog.Dialog;
import nayasis.common.util.FileUtil;
import nayasis.common.util.StringUtil;
import emuLoader.biz.FileData;
import emuLoader.biz.GameData;

/**
 * Rom Selector
 * 
 * @author nayasis
 *
 */
public class RomSelector implements Initializable {
	
	@FXML public Label             lblStatus; 

	@FXML public TextField         txtCategory; 
	@FXML public TextField         txtSearchPath;
	@FXML public TextField         txtFileNameFilter;

	@FXML public ComboBox<Integer> rawCmbScanDepth;
	      public NfxCombo          cmbScanDepth;
	
	@FXML public TableView<?>      rawTblRomList;
	      public NfxTable          tblRomList;
	
	@FXML public Button            btnSearch;
	@FXML public Button            btnShiftLower;
	@FXML public Button            btnShiftUpper;
	@FXML public Button            btnApply;
	@FXML public Button            btnLoad;
	@FXML public Button            btnSave;
	
	private enum SHIFT { LOWER, NONE, UPPER };

	private String searchPath     = null;
	private int    scanDepth      = 0;
	private String fileNameFilter = null;
	private SHIFT  shiftStatus    = SHIFT.NONE;
	
	@Override
	public void initialize( URL url, ResourceBundle resourceBundle ) {

		// 테이블 세팅
		tblRomList = new NfxTable( rawTblRomList, "dir", "file" );
		
		tblRomList.addEventKeypress( new EventHandler<KeyEvent>() {
			public void handle(KeyEvent event) {
				
				NLogger.debug.println( "#A : row[@], col[@]", tblRomList.getFocusedRowIndex(), tblRomList.getFocusedColumnIndex() );
				
				NLogger.debug.println( "#A : [@] @", event.isAltDown(), event.getCode() );				
			}
		});

		tblRomList.addEventKeyup( new EventHandler<KeyEvent>() {
			public void handle(KeyEvent event) {
				NLogger.debug.println( "#B : row[@], col[@]", tblRomList.getFocusedRowIndex(), tblRomList.getFocusedColumnIndex() );
				NLogger.debug.println( "#B : [@] @", event.isAltDown(), event.getCode() );				
			}
		});

		tblRomList.addEventClick( new EventHandler<MouseEvent>() {
			public void handle(MouseEvent event) {
				NLogger.debug.println( "#C : row[@], col[@]", tblRomList.getFocusedRowIndex(), tblRomList.getFocusedColumnIndex() );
				NLogger.debug.println( "#C : [@,@]", event.getX(), event.getY() );				
				
			}
		});
		
		
		GamePadEventManager.getInstance().addEvent( new GamePadEventHandler() {
			public void handle( GamePadEvent event ) {
				
				tblRomList.getInstance().requestFocus();
				
				int focusedRowIndex = tblRomList.getFocusedRowIndex();
				
				switch( event.getPovValue() ) {
				    case UP    : focusedRowIndex--;     break;
				    case DOWN  : focusedRowIndex++;     break;
				    case RIGHT : focusedRowIndex += 10; break;
				    case LEFT  : focusedRowIndex -= 10; break;
				    default    : return;
				}
				
				tblRomList.select( focusedRowIndex );
				
			}
		});
		
		// 검색조건 콤보박스 세팅
		cmbScanDepth = new NfxCombo( rawCmbScanDepth );
		for( int i = 0; i <= 10; i++ ) {
			cmbScanDepth.addItem( i );
		}
		cmbScanDepth.setValue( 0 );

		// 버튼 활성화상태 컨트롤
		btnShiftLower.setDisable( true );
		btnShiftUpper.setDisable( true );
		btnApply.setDisable( true );
		btnSave.setDisable( true );
		
		// for test
		txtCategory.setText( "SuperFamicom" );
		//txtSearchPath.setText( "//NAS/emul/MegaDrive/roms" );
		txtSearchPath.setText( "//NAS/emul/SuperFamicom/roms" );
		cmbScanDepth.setValue( 2 );
		
		try {
			load( null );
		} catch (IOException e) {
			e.printStackTrace();
		}
	
	}
	
	@FXML
	public void searchGame( ActionEvent event ) throws IOException {

		searchPath     = txtSearchPath.getText();
		fileNameFilter = txtFileNameFilter.getText();
		scanDepth      = (int) cmbScanDepth.getValue();

		if( StringUtil.isEmpty(searchPath) ) {
			Dialog.alert( "검색할 경로가 입력되지 않았습니다." );
			return;
		}
		
		searchGame();

	}

	/**
	 * Search Game List
	 * 
	 * @throws IOException when occuring IO error
	 */
	private void searchGame() throws IOException {

		FileData dataManager = new FileData();
		
		NMultiData romPath = dataManager.getRomPath( searchPath, fileNameFilter, scanDepth );
		
		tblRomList.bind( romPath );

		lblStatus.setText( StringUtil.format("Done game search. ( @ count )", tblRomList.getRowSize()) );
		
		if( romPath.size() == 0 || StringUtil.isEmpty(romPath.get(0).getString("file")) ) {
			btnShiftLower.setDisable( true );
			btnShiftUpper.setDisable( true );
			btnApply.setDisable( true );

		} else {
			btnShiftLower.setDisable( false );
			btnShiftUpper.setDisable( false );
			btnApply.setDisable( true );
			btnSave.setDisable( false );
			
		}

		shiftStatus = SHIFT.NONE;
		
	}

	@FXML
	public void shiftLower( ActionEvent event ) {
		
		NMultiData rows = tblRomList.getAllData();

		for( NData row : rows ) {
			
			Path path = (Path) row.get( "path" );
			
			String dir = path.toAbsolutePath().toString();
			
			row.put( "dir", FileUtil.removeExtention(dir) );
			
		}

		tblRomList.bind( rows );
		
		btnShiftLower.setDisable( true );
		btnShiftUpper.setDisable( false );
		btnApply.setDisable( false );

		shiftStatus = SHIFT.LOWER;

	}

	@FXML
	public void shiftUpper( ActionEvent event ) {
		
		NMultiData rows = tblRomList.getAllData();
		
		for( NData row : rows ) {
			
			Path path = (Path) row.get( "path" );
			
			String dir = path.getParent().getParent().toString();
			
			row.put( "dir", dir );
			
		}
		
		tblRomList.bind( rows );
		
		btnShiftLower.setDisable( false );
		btnShiftUpper.setDisable( true );
		btnApply.setDisable( false );
		
		shiftStatus = SHIFT.UPPER;
		
	}

	@FXML
	public void apply( ActionEvent event ) throws IOException {
		
		if( ! Dialog.confirm("변경작업을 진행하시겠습니까 ?") ) return;
			
		NMultiData rows = tblRomList.getAllData();
		
		switch( shiftStatus ) {
		
		case LOWER :
			shiftDirectoryPathToLower( rows );
			scanDepth++;
			break;
		
		case UPPER :
			shiftDirectoryPathToUpper( rows );
			scanDepth--;
			break;

		default:
			break;
			
		}
		
		searchGame();
		
		cmbScanDepth.setValue( scanDepth );
		
		Dialog.alert( "작업을 완료하였습니다." );
		
	}
	
	private void shiftDirectoryPathToLower( NMultiData rows ) throws IOException {

		for( NData row : rows ) {
			
			Path path = (Path) row.get( "path" );
			String dir = row.getString( "dir" );
			
			try {
				FileUtil.moveFile( path.toString(), dir );
			} catch ( IOException e ) {
				Dialog.alert( "Shift Lower 작업 도중 오류가 발생하였습니다." );
				throw e;
			}
			
		}
		
	}

	private void shiftDirectoryPathToUpper( NMultiData rows ) throws IOException {
		
		for( NData row : rows ) {
			
			Path path = (Path) row.get( "path" );
			String dir = row.getString( "dir" );

			try {
				FileUtil.moveFile( path.toString(), dir );
				
				try {
					FileUtil.deleteFile( path.getParent().toString() );
				} catch( IOException e ) {}
				
			} catch ( IOException e ) {
				Dialog.alert( "Shift Upper 작업 도중 오류가 발생하였습니다." );
				throw e;
			}
			
		}
		
	}

	/**
	 * 검색폴더를 설정하는 DirectoryPicker를 호출한다.
	 * 
	 * @param event
	 * @throws IOException
	 */
	@FXML
	public void openDirectoryPicker( ActionEvent event ) {

		DirectoryChooser picker = new DirectoryChooser();

		picker.setTitle( "Set search root directory" );
		picker.setInitialDirectory( new File(txtSearchPath.getText()) );

		File pickedFile = picker.showDialog( null );
		
		if( pickedFile == null ) return;

		txtSearchPath.setText( pickedFile.getPath() );

	}

	@FXML
	public void save( ActionEvent event ) throws IOException {

		if( tblRomList.getRowSize() == 0 ) {
			Dialog.alert( "저장할 데이터가 없습니다." );
			return;
		}

		String emulKind = txtCategory.getText().trim();
		
		if( emulKind.length() == 0 ) {
			Dialog.alert( "@는 필수 입력 항목입니다.", "EmulCategory" );
			txtCategory.focusedProperty();
			return;
		}
		
		if( ! Dialog.confirm("데이터를 저장하시겠습니까 ?") ) return;
			
		GameData biz = new GameData();
		
		biz.createGameInfo( emulKind, tblRomList.getAllData() );

	}

	@FXML
	public void load( ActionEvent event ) throws IOException {

		String emulKind = txtCategory.getText().trim();
		
		if( emulKind.length() == 0 ) {
			Dialog.alert( "@는 필수 입력 항목입니다.", "EmulCategory" );
			txtCategory.focusedProperty();
			return;
		}
		
//		if( ! Dialog.confirm("데이터를 조회하시겠습니까 ?") ) return;
			
		GameData biz = new GameData();
		
		NMultiData romPath = new NMultiData();
		
		try {

		    romPath = biz.retrieveGameFile( emulKind );
		    
		    tblRomList.bind( romPath );
		    
		} catch ( Exception e ) {
		    
		}
		

		lblStatus.setText( StringUtil.format("Done game search. ( @ count )", tblRomList.getRowSize()) );
		
		if( romPath.size() == 0 || StringUtil.isEmpty(romPath.get(0).getString("file")) ) {
			btnShiftLower.setDisable( true );
			btnShiftUpper.setDisable( true );
			btnApply.setDisable( true );

		} else {
			btnShiftLower.setDisable( false );
			btnShiftUpper.setDisable( false );
			btnApply.setDisable( true );
			btnSave.setDisable( false );
			
		}

		shiftStatus = SHIFT.NONE;
		
	}
	
}